package bma.common.langutil.jmshell.jvm;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import bma.common.langutil.concurrent.BMAThreadPoolExecutor;
import bma.common.langutil.concurrent.ThreadPoolSquare;
import bma.common.langutil.core.DateTimeUtil;
import bma.common.langutil.core.ObjectPair;
import bma.common.langutil.jmshell.Session;
import bma.common.langutil.jmshell.cmdopt.CommandOptionParser;
import bma.common.langutil.jmshell.command.AbstractSimpleCommandProcessor;
import bma.common.langutil.jmshell.common.JMSPager;

public class JVMThreadPoolCommand extends AbstractSimpleCommandProcessor {

	private static final String DATA_KEY = "@jvm_threadpool";
	private static final String PAGER_KEY = DATA_KEY;

	public JVMThreadPoolCommand() {
		super("threadpool");
	}

	@Override
	public CommandOptionParser createCommandOption(Session session) {
		CommandOptionParser r = new CommandOptionParser();
		r.addIntegerOption('s', "size", "show threadpool info page size");
		r.addIntegerOption('p', "pos",
				"show threadpool from which position, default last position");
		r.addBooleanOption('r', "reset", "clear threadpool info cache");
		r.addStringOption('f', "filter", "threadpool name filter");
		r.addBooleanOption('c', "create", "create threadpool info");
		return r;
	}

	@Override
	public boolean processCommand(Session s, String cmd,
			CommandOptionParser options) {
		boolean reset = options.getOptionValue("reset", Boolean.FALSE);
		if (reset) {
			resetPager(s);
			return true;
		}

		boolean create = options.getOptionValue("create", Boolean.FALSE);
		if (create) {
			Collection<String> filters = options.getOptionValues("filter",
					String.class);
			createPager(s, filters);
			return true;
		}
		int sz = options.getOptionValue("size", new Integer(-1));
		if (sz > 0) {
			JMSPager pager = JMSPager.getData(s, PAGER_KEY, true);
			pager.setSize(sz);
		}
		threadpoolInfo(s, options);
		return true;
	}

	public void threadpoolInfo(Session s, CommandOptionParser options) {

		JMSPager pager = JMSPager.getData(s, PAGER_KEY, false);
		if (pager == null) {
			createPager(s, null);
			pager = JMSPager.getData(s, PAGER_KEY, false);
		}
		int total = pager == null ? 0 : pager.total();

		s.writeln("[threadpool " + total + "]");
		if (pager != null) {
			int pos = options.getOptionValue("pos", new Integer(-1));
			pager.show(s, pos, -1, new JMSPager.Render<ObjectPair>() {
				@Override
				public void show(Session s, ObjectPair obj, int pos) {
					showThreadPoolInfo(s, (String) obj.getValue(),
							(Object) obj.getAttribute());
				}
			}, ObjectPair.class);
		}
		s.writeln("[threadpool end]");
	}

	protected String runState(int rs) {
		switch (rs) {
		case 0:
			return "RUNNING";
		case 1:
			return "SHUTDOWN";
		case 2:
			return "STOP";
		case 3:
			return "TERMINATED";
		default:
			return "UNKNOW";
		}
	}

	protected void showThreadPoolInfo(Session s, String name, Object threadPool) {
		StringBuilder sb = new StringBuilder();
		sb.append("[").append(name).append("]\n");
		if (threadPool != null) {
			TreeMap<String, Object> props = new TreeMap<String, Object>();
			if (threadPool instanceof BMAThreadPoolExecutor) {
				BMAThreadPoolExecutor ex = (BMAThreadPoolExecutor) threadPool;
				props.put("coreSize", ex.getCorePoolSize());
				props.put("maxSize", ex.getMaximumPoolSize());
				props.put("activeCount", ex.getActiveCount());
				props.put("largestSize", ex.getLargestPoolSize());
				props.put("task",
						ex.getCompletedTaskCount() + "/" + ex.getTaskCount());
				props.put("keepAlive", DateTimeUtil.formatPeriod(ex
						.getKeepAliveTime(TimeUnit.MILLISECONDS)));
				props.put("queue", ex.getQueue().size());
				props.put("runState", runState(ex.getRunState()));
			} else if (threadPool instanceof ThreadPoolExecutor) {
				ThreadPoolExecutor ex = (ThreadPoolExecutor) threadPool;
				props.put("coreSize", ex.getCorePoolSize());
				props.put("maxSize", ex.getMaximumPoolSize());
				props.put("activeCount", ex.getActiveCount());
				props.put("largestSize", ex.getLargestPoolSize());
				props.put("completedTask", ex.getCompletedTaskCount());
				props.put("keepAlive", DateTimeUtil.formatPeriod(ex
						.getKeepAliveTime(TimeUnit.MILLISECONDS)));
				props.put("queue", ex.getQueue().size());
			}
			if (props.isEmpty()) {
				sb.append(threadPool);
			} else {
				Iterator<Map.Entry<String, Object>> it = props.entrySet()
						.iterator();
				while (it.hasNext()) {
					Map.Entry<String, Object> e = it.next();
					sb.append(e.getKey()).append("=").append(e.getValue());
					if (it.hasNext())
						sb.append(", ");
				}
			}
		}
		s.writeln(sb.toString());
	}

	protected void createPager(Session s, Collection<String> filters) {

		List<ObjectPair<String, Object>> tplist = ThreadPoolSquare.list();
		Iterator<ObjectPair<String, Object>> it = tplist.iterator();
		if (filters != null && filters.size() > 0) {
			while (it.hasNext()) {
				String name = it.next().getValue();
				boolean fmatch = false;
				for (String fi : filters) {
					if (name.indexOf(fi) != -1) {
						fmatch = true;
						break;
					}
				}
				if (!fmatch) {
					it.remove();
				}
			}
		}

		JMSPager pg = JMSPager.getData(s, PAGER_KEY, true);
		pg.init(tplist);

		s.writeln("threadpool info created, use 'threadpool' to view");
	}

	protected void resetPager(Session s) {
		JMSPager pg = JMSPager.getData(s, PAGER_KEY, false);
		if (pg != null) {
			pg.reset();
		}
		s.writeln("threadpool info reset");
	}
}